/*
 * Copyright (c) 2013, SRI International
 * All rights reserved.
 * Licensed under the The BSD 3-Clause License;
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 * 
 * http://opensource.org/licenses/BSD-3-Clause
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 
 * Neither the name of the aic-web-praise nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.sri.ai.lpitools.cobra.server.data.implementations;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import com.google.gson.Gson;
import com.sri.ai.lpitools.cobra.gwtutil.dataobjects.shared.EvidenceInfo;
import com.sri.ai.lpitools.cobra.gwtutil.dataobjects.shared.LWPException;
import com.sri.ai.lpitools.cobra.gwtutil.dataobjects.shared.ModelInfo;
import com.sri.ai.lpitools.cobra.gwtutil.dataobjects.shared.QueryInfo;
import com.sri.ai.lpitools.cobra.gwtutil.dataobjects.shared.UserInfo;
import com.sri.ai.lpitools.cobra.server.data.api.DataInterface;

public class DataStubImp implements DataInterface {

	List<UserInfo> users;
	HashMap<String, List<ModelInfo>> models;
	HashMap<String, List<QueryInfo>> queries;
	HashMap<String, List<EvidenceInfo>> evidence;
	
	public DataStubImp(){
		initUser();
		initModels();
		initQueries();
		initEvidence();
		
	}
	private void initEvidence() {
		evidence = new HashMap<String, List<EvidenceInfo>> ();
		
		EvidenceInfo evidence1 = new EvidenceInfo();
		evidence1.setEvidence("NA");
		evidence1.setEvidenceTitle("E1");
		
		EvidenceInfo evidence2 = new EvidenceInfo();
		evidence2.setEvidence("NA");
		evidence2.setEvidenceTitle("E2"); 
		
		evidence1.setUser("Bilbo");
		evidence2.setUser("Bilbo");
		List<EvidenceInfo> bList = new ArrayList<EvidenceInfo>();
		bList.add(evidence1);
		bList.add(evidence2);
		evidence.put("Bilbo", bList);
		
		evidence1.setUser("Frodo");
		evidence2.setUser("Frodo");
		List<EvidenceInfo> fList = new ArrayList<EvidenceInfo>();
		fList.add(evidence1);
		fList.add(evidence2);
		evidence.put("Frodo", fList);		
		
		evidence1.setUser("Gimili");
		evidence2.setUser("Gimili");
		List<EvidenceInfo> gList = new ArrayList<EvidenceInfo>();
		gList.add(evidence1);
		gList.add(evidence2);
		evidence.put("Gimili", gList);	
		
		evidence1.setUser("Legolas");
		evidence2.setUser("Legolas");
		List<EvidenceInfo> lList = new ArrayList<EvidenceInfo>();
		lList.add(evidence1);
		lList.add(evidence2);
		evidence.put("Legolas", lList);	
		
	}
	private void initQueries() {
		queries= new HashMap<String, List<QueryInfo>>() ;
		QueryInfo query1 = new QueryInfo();
		query1.setQuery("belief([rich(bob)])");
		query1.setQueryTitle("Is Bob Rich?");
		
		QueryInfo query2 = new QueryInfo();
		query2.setQuery("belief([rich(Ann)])");
		query2.setQueryTitle("Is Ann Rich?"); 
		
		QueryInfo query3 = new QueryInfo();
		query3.setQuery("belief([sick(X)])");
		query3.setQueryTitle("Is Sick?"); 	
		
		query1.setUser("Bilbo");
		query2.setUser("Bilbo");
		query3.setUser("Bilbo");
		List<QueryInfo> bList = new ArrayList<QueryInfo>();
		bList.add(query1);
		bList.add(query2);
		bList.add(query3);
		queries.put("Bilbo", bList);
		
		query1.setUser("Frodo");
		query2.setUser("Frodo");
		List<QueryInfo> fList = new ArrayList<QueryInfo>();
		fList.add(query1);
		fList.add(query2);
		queries.put("Frodo", fList);		
		
		query1.setUser("Gimili");
		query2.setUser("Gimili");
		List<QueryInfo> gList = new ArrayList<QueryInfo>();
		gList.add(query1);
		gList.add(query2);
		queries.put("Gimili", gList);	
		
		query1.setUser("Legolas");
		query2.setUser("Legolas");
		List<QueryInfo> lList = new ArrayList<QueryInfo>();
		lList.add(query1);
		lList.add(query2);
		queries.put("Legolas", lList);	
	}
	private void initModels() {
		String model = "'Gave Treasure To', 'An example of how hard it is to model things without aggregate factors.', sort(People, Unknown, { ann, bob }), sort(Treasure, Unknown, { gold, silver, diamonds }), randomVariable(gaveTreasureTo, 3, People, Treasure, People), randomVariable(owns, 2, People, Treasure, Boolean), randomVariable(rich, 1, People, Boolean), parfactors(union({{(on X in People, Y in People, Z in Treasure) [if gaveTreasureTo(X,Z,Y) then (if owns(Y,Z) then 1 else 0)  else 1]}}, {{(on X in People, Z in Treasure) [if owns(X,Z) then if rich(X) then 1 else 0 else 1] }}))";
		String model2Sample = "'Epidemic and Sick with Symptons Example', 'An example of the interplay between symptoms.', sort(People, 10, { bob, dave, rodrigo, ciaran }), randomVariable(epidemic, 0), randomVariable(sick, 1, People, Boolean), "
				+ "randomVariable(fever, 1, People, Boolean), randomVariable(rash, 1, People, Boolean), randomVariable(notAtWork, 1, People, Boolean), "
				+"parfactors(union({[if epidemic then 0.001 else 0.999]}, {{(on X in People) [if epidemic then if sick(X) then 0.6 else 0.4 else if sick(X) then 0.05 else 0.95]}}, {{(on X in People) [if sick(X) then if fever(X) then 0.7 else 0.3 else if fever(X) then 0.01 else 0.99]}}, {{(on X in People) [if sick(X) then if rash(X) then 0.6 else 0.4 else if rash(X) then 0.07 else 0.93]}}, {{(on X in People) [if sick(X) then if notAtWork(X) then 0.8 else 0.2 else if notAtWork(X) then 0.05 else 0.95]}}, {[if notAtWork(dave) then 0.001 else 0.999]}))";

		models= new HashMap<String, List<ModelInfo>>() ;
		
		ModelInfo model1 = new ModelInfo("Bilbo", "Bilbo Model 1", "Model 1 for Bilbo", model+"");
		ModelInfo model2 = new ModelInfo("Bilbo", "Bilbo Model 2", "Model 2 for Bilbo", model2Sample+"");		
		List<ModelInfo> bList = new ArrayList<ModelInfo>();
		bList.add(model1);
		bList.add(model2);
		models.put("Bilbo", bList);

		ModelInfo model3 = new ModelInfo("Frodo", "Frodo Model 1", "Model 1 for Frodo", model+"");
		ModelInfo model4 = new ModelInfo("Frodo", "Frodo Model 2", "Model 2 for Frodo", model+"");		
		List<ModelInfo> fList = new ArrayList<ModelInfo>();
		fList.add(model3);
		fList.add(model4);
		models.put("Frodo", fList);
		
		ModelInfo model5 = new ModelInfo("Gimili", "Gimili Model 1", "Model 1 for Gimili", model+"");
		ModelInfo model6 = new ModelInfo("Gimili", "Gimili Model 2", "Model 2 for Gimili", model+"");		
		List<ModelInfo> gList = new ArrayList<ModelInfo>();
		gList.add(model5);
		gList.add(model6);
		models.put("Gimili", gList);
		
		ModelInfo model7 = new ModelInfo("Legolas", "Legolas Model 1", "Model 1 for Legolas", model+"");
		ModelInfo model8 = new ModelInfo("Legolas", "Legolas Model 2", "Model 2 for Legolas", model+"");		
		List<ModelInfo> lList = new ArrayList<ModelInfo>();
		lList.add(model7);
		lList.add(model8);
		models.put("Legolas", lList);
		
	}
	private void initUser() {
		users = new ArrayList<UserInfo>();
		UserInfo user1 = new UserInfo("Bilbo", true);
		UserInfo user2 = new UserInfo("Frodo", true);
		UserInfo user3 = new UserInfo("Gimili", false);		
		UserInfo user4 = new UserInfo("Legolas", false);	
		users.add(user1);
		users.add(user2);
		users.add(user3);
		users.add(user4);
	}

	@Override
	public String getModelList(String user) throws LWPException {
		
		if(models.containsKey(user)){
			List<ModelInfo> list = models.get(user);
			String modelString = new Gson().toJson(list);
			return modelString;		
		} else {
			throw new LWPException("unknown user");
		}
	}

	@Override
	public String openModel(String user, String modelTitle) {
		
		if(models.containsKey(user)){
			List<ModelInfo> list = models.get(user);
			ModelInfo model = null;
			for(ModelInfo current: list){
				if(current.getModelTitle().equalsIgnoreCase(modelTitle)){
					model = current;
					break;
				}
			}
			String modelString = "Not Valid";
			if(model != null){
				modelString = new Gson().toJson(model);
			}
			return modelString;	
		}
		else{
			return "Not Valid";
		}
		
	}

	@Override
	public boolean saveModel(String user, String title, String model) {
		List<ModelInfo> userModels = models.get(user);
		ModelInfo newModel =new Gson().fromJson(model, ModelInfo.class);
		boolean result = false;
		boolean found = false;
		for(int i = 0; i<userModels.size(); i++){
			if(userModels.get(i).getModelTitle().equalsIgnoreCase(title)){
				userModels.remove(i);
				result = userModels.add(newModel);
				found = true;
				break;
			}
		}
		if(!found){
			result = userModels.add(newModel);
		}
		models.put(user, userModels);
		
		return result;
	}

	@Override
	public boolean saveModelInfo(String user, String title, String model) {
		List<ModelInfo> userModels = models.get(user);
		ModelInfo newModel =new Gson().fromJson(model, ModelInfo.class);
		boolean result = false;
		boolean found = false;
		for(int i = 0; i<userModels.size(); i++){
			if(userModels.get(i).getModelTitle().equalsIgnoreCase(title)){
				ModelInfo currentModel = userModels.remove(i);
				currentModel.setShortDescription(newModel.getShortDescription());
				result = userModels.add(currentModel);
				found = true;
				break;
			}
		}
		if(!found){
			result = userModels.add(newModel);
		}
		models.put(user, userModels);
		
		return result;
	}
	
	@Override
	public boolean saveModelBody(String user, String title, String model) {
		List<ModelInfo> userModels = models.get(user);
		ModelInfo newModel =new Gson().fromJson(model, ModelInfo.class);
		boolean result = false;
		boolean found = false;
		for(int i = 0; i<userModels.size(); i++){
			if(userModels.get(i).getModelTitle().equalsIgnoreCase(title)){
				ModelInfo currentModel = userModels.remove(i);
				currentModel.setModelText(newModel.getModelText());
				result = userModels.add(currentModel);
				found = true;
				break;
			}
		}
		if(!found){
			result = userModels.add(newModel);
		}
		models.put(user, userModels);
		
		return result;
	}	
	
	@Override
	public boolean deleteModel(String user, String modelTitle) {
		boolean result = false;
		List<ModelInfo> userModels = models.get(user);
		for(int index = 0; index<userModels.size(); index++){
			ModelInfo current = userModels.get(index);
			if(current.getModelTitle().equalsIgnoreCase(modelTitle)){
				userModels.remove(index);
				result = true;
				break;
			}
		}
		return result;
	}

	@Override
	public boolean saveQuery(String user, String title, String query) {
		List<QueryInfo> userData = queries.get(user);
		QueryInfo newData =new Gson().fromJson(query, QueryInfo.class);
		boolean result = false;
		boolean found = false;
		for(int i = 0; i<userData.size(); i++){
			if(userData.get(i).getQueryTitle().equalsIgnoreCase(title)){
				userData.remove(i);
				result = userData.add(newData);
				found = true;
				break;
			}
		}
		if(!found){
			result = userData.add(newData);
		}
		queries.put(user, userData);
		
		return result;
	}

	@Override
	public String listQueries(String user) {
		if(queries.containsKey(user)){
			List<QueryInfo> list = queries.get(user);
			String queryJSON = new Gson().toJson(list);
			return queryJSON;	
		}
		else{
			return "Not Valid";
		}
	}

	@Override
	public String getQuery(String user, String queryTitle) {
		if(queries.containsKey(user)){
			List<QueryInfo> list = queries.get(user);
			QueryInfo query = null;
			for(QueryInfo current: list){
				if(current.getQueryTitle().equalsIgnoreCase(queryTitle)){
					query= current;
					break;
				}
			}
			String queryJSON = "Not Valid";
			if(query != null){
				queryJSON = new Gson().toJson(query);
			}
			return queryJSON;
		}
		else{
			return "Not Valid";
		}
		
	}

	@Override
	public boolean deleteQuery(String user, String queryTitle) {
		boolean result = false;
		List<QueryInfo> userData =queries.get(user);
		for(int index = 0; index<userData.size(); index++){
			QueryInfo current = userData.get(index);
			if(current.getQueryTitle().equalsIgnoreCase(queryTitle)){
				userData.remove(index);
				result = true;
				break;
			}
		}
		return result;
	}

	@Override
	public String listEvidences(String user) {
		if(evidence.containsKey(user)){
			List<EvidenceInfo> list = evidence.get(user);
			String evidenceJSON = new Gson().toJson(list);

			return evidenceJSON;	
		}
		else{
			return "Not Valid";
		}
		

	}

	@Override
	public String getEvidence(String user, String evidenceTitle) {
		if(evidence.containsKey(user)){
			List<EvidenceInfo> list = evidence.get(user);
			EvidenceInfo evidence = null;
			for(EvidenceInfo current: list){
				if(current.getEvidenceTitle().equalsIgnoreCase(evidenceTitle)){
					evidence= current;
					break;
				}
			}
			String evidenceJSON = "Not Valid";
			if(evidence != null){
				evidenceJSON = new Gson().toJson(evidence);
			}
			return evidenceJSON;
		}
		else{
			return "Not Valid";
		}

	}

	@Override
	public boolean saveEvidence(String user, String title, String evidenceString) {
		List<EvidenceInfo> userData = evidence.get(user);
		EvidenceInfo newData =new Gson().fromJson(evidenceString, EvidenceInfo.class);
		boolean result = false;
		boolean found = false;
		for(int i = 0; i<userData.size(); i++){
			if(userData.get(i).getEvidenceTitle().equalsIgnoreCase(title)){
				userData.remove(i);
				result = userData.add(newData);
				found = true;
				break;
			}
		}
		if(!found){
			result = userData.add(newData);
		}
		evidence.put(user, userData);
		
		return result;
	}

	@Override
	public boolean deleteEvidence(String user, String evidenceTitle) {
		boolean result = false;
		List<EvidenceInfo> userData =evidence.get(user);
		for(int index = 0; index<userData.size(); index++){
			EvidenceInfo current = userData.get(index);
			if(current.getEvidenceTitle().equalsIgnoreCase(evidenceTitle)){
				userData.remove(index);
				result = true;
				break;
			}
		}
		return result;
	}

	@Override
	public String checkUser(String user) {
		
		String userJSON ="Not Valid";
		for(UserInfo current: users){
			if(current.getUser().equalsIgnoreCase(user)){
				userJSON = new Gson().toJson(current);
				break;
			}
		}
		return userJSON;
	}

	@Override
	public boolean saveUser(String user) {
		boolean result = false;
		UserInfo userInfo = new Gson().fromJson(user, UserInfo.class);
		for(int index = 0; index < users.size(); index++){
			UserInfo currentUser = users.get(index);
			if(currentUser.getUser().equalsIgnoreCase(userInfo.getUser())){
				users.remove(index);
				users.add(index, userInfo);
				result = true;
				break;
			}
		}
		if(!result){
			users.add(userInfo);
			result = true;			
		}
		return result;
	}

	@Override
	public boolean deleteUser(String user) {

		boolean result = false;
		for(int index = 0; index < users.size(); index++){
			UserInfo currentUser = users.get(index);
			if(currentUser.getUser().equalsIgnoreCase(user)){
				users.remove(index);
				result = true;
				break;
			}
		}
		return result;
	}

	@Override
	public String getUsers() {
		String userJSON = new Gson().toJson(users);
		
		return userJSON;

	}

	public void close() {}

}
